import json
import numpy as np
from peps_download import PepsDownload
import sys


class PepsDownloadBest(PepsDownload):
    def __init__(self, location=None, auth=None, write_dir='.', collection='S2', product_type="", sensor_mode="",
                 no_download=False, start_date=None, tile=None, lat=None, lon=None, latmin=None, latmax=None,
                 lonmin=None, lonmax=None, orbit=None, end_date='9999-01-01', search_json_file=None, windows=True,
                 clouds=100, sat=None, extract=None, best_number=1):
        """
        该类用于下载指定个数的最优数据
        :param location: town name (pick one which is not too frequent to avoid confusions)
        :param auth: Peps account and password file
        :param write_dir: Path where the products should be downloaded
        :param collection: Collection within theia collections", choices=['S1', 'S2', 'S2ST', 'S3']
        :param product_type: GRD, SLC, OCN (for S1) | S2MSI1C S2MSI2A S2MSI2Ap (for S2)
        :param sensor_mode: EW, IW , SM, WV (for S1) | INS-NOBS, INS-RAW (for S3)
        :param no_download: Do not download products, just print curl command
        :param start_date: start date, fmt('2015-12-22')
        :param tile: Sentinel-2 tile number
        :param lat: latitude in decimal degrees
        :param lon: longitude in decimal degrees
        :param latmin: min latitude in decimal degrees
        :param latmax: max latitude in decimal degrees
        :param lonmin: min longitude in decimal degrees
        :param lonmax: max longitude in decimal degrees
        :param orbit: Orbit Path number
        :param end_date: end date, fmt('2015-12-23')
        :param search_json_file: Output search JSON filename
        :param windows: For windows usage
        :param clouds: Maximum cloud coverage
        :param sat: S1A,S1B,S2A,S2B,S3A,S3B
        :param extract: Extract and remove zip file after download
        :param best_number: Best file number : 2
        """
        self.best_number = best_number
        super().__init__(location, auth, write_dir, collection, product_type, sensor_mode, no_download, start_date,
                         tile, lat, lon, latmin, latmax, lonmin, lonmax, orbit, end_date, search_json_file, windows,
                         clouds, sat, extract)

    # 重写了peps_download的parse_catalog函数，在元数据json文件的解析过程中增加了最优数据判断代码，
    # 判断最优的方式为 文件大小*（1-云量）最大
    def parse_catalog(self):
        # Filter catalog result
        with open(self.search_json_file) as data_file:
            data = json.load(data_file)

        if 'ErrorCode' in data:
            print(data['ErrorMessage'])
            sys.exit(-2)

        # Sort data
        download_dict = {}
        storage_dict = {}
        size_dict = {}
        if len(data["features"]) > 0:
            for i in range(len(data["features"])):
                prod = data["features"][i]["properties"]["productIdentifier"]
                feature_id = data["features"][i]["id"]
                try:
                    storage = data["features"][i]["properties"]["storage"]["mode"]
                    platform = data["features"][i]["properties"]["platform"]
                    resourceSize = int(data["features"][i]["properties"]["resourceSize"])
                    if storage == "unknown":
                        print('found a product with "unknown" status : %s' % prod)
                        print("product %s cannot be downloaded" % prod)
                        print('please send and email with product name to peps admin team : exppeps@cnes.fr')
                    else:
                        # recup du numero d'orbite
                        orbitN = data["features"][i]["properties"]["orbitNumber"]
                        if platform == 'S1A':
                            # calcul de l'orbite relative pour Sentinel 1A
                            relativeOrbit = ((orbitN - 73) % 175) + 1
                        elif platform == 'S1B':
                            # calcul de l'orbite relative pour Sentinel 1B
                            relativeOrbit = ((orbitN - 27) % 175) + 1

                        if self.orbit is not None:
                            if platform.startswith('S2'):
                                if prod.find("_R%03d" % self.orbit) > 0:
                                    download_dict[prod] = feature_id
                                    storage_dict[prod] = storage
                                    size_dict[prod] = resourceSize

                            elif platform.startswith('S1'):
                                if relativeOrbit == self.orbit:
                                    download_dict[prod] = feature_id
                                    storage_dict[prod] = storage
                                    size_dict[prod] = resourceSize
                        else:
                            download_dict[prod] = feature_id
                            storage_dict[prod] = storage
                            size_dict[prod] = resourceSize

                except:
                    pass

            # cloud cover criterium:
            # Obtain the data with the least cloud cover in the first half of the month and the second half of the month
            if self.collection[0:2] == 'S2':
                use_data_array = np.zeros((len(data["features"])))
                for i in range(len(data["features"])):
                    prod = data["features"][i]["properties"]["productIdentifier"]
                    clouds_Cover = data["features"][i]["properties"]["cloudCover"]
                    resourceSize = int(data["features"][i]["properties"]["resourceSize"])
                    use_data = resourceSize * (1 - clouds_Cover)
                    use_data_array[i] = use_data

                use_data_sort = np.sort(use_data_array)
                print(use_data_sort)
                use_data_th = use_data_sort[-self.best_number]
                for i in range(len(data["features"])):
                    prod = data["features"][i]["properties"]["productIdentifier"]
                    if data["features"][i]["properties"]["cloudCover"] > self.clouds:
                        del download_dict[prod], storage_dict[prod], size_dict[prod]
                        continue
                    clouds_Cover = data["features"][i]["properties"]["cloudCover"]
                    resourceSize = int(data["features"][i]["properties"]["resourceSize"])
                    use_data = resourceSize * (1 - clouds_Cover)

                    if use_data < use_data_th:
                        del download_dict[prod], storage_dict[prod], size_dict[prod]

            # selecion of specific satellite
            if self.sat != None:
                for i in range(len(data["features"])):
                    prod = data["features"][i]["properties"]["productIdentifier"]
                    if data["features"][i]["properties"]["platform"] != self.sat:
                        try:
                            del download_dict[prod], storage_dict[prod], size_dict[prod]
                        except KeyError:
                            pass

            for prod in download_dict.keys():
                print(prod, storage_dict[prod])
        else:
            print(">>> no product corresponds to selection criteria")
            sys.exit(-1)
        return (prod, download_dict, storage_dict, size_dict)
